package com.zhu.rtda.heap.constant;

import com.zhu.rtda.heap.ClassLoader;
import com.zhu.rtda.heap.InstanceKlass;

/**
 * 符号引用基类（对应 Go 的 SymRef）
 *
 * 在类加载过程中，尚未解析的类、字段、方法引用都以符号引用的形式存在。
 * 符号引用包含一个类名（className）和指向运行时常量池的指针（cp）。
 * 只有在首次使用时才会进行解析（resolve），转换为直接引用。
 */
public abstract class SymRef implements Constant{
    /**
     * 类的全限定名（如 java/lang/Object），来自 class 文件常量池
     */
    protected String className;
    /**
     * 解析后的类对象（直接引用）
     * 初始为 null，调用 resolveClassRef 后赋值
     */
    protected InstanceKlass instanceKlass;

    /**
     * 指向运行时常量池，表示这个符号引用是属于哪个常量池
     */
    protected RuntimeConstantPool runtimeConstantPool;



    /**
     * 获取解析后的类对象
     * 如果尚未解析，则先进行解析
     *
     * @return 解析后的类
     */
    public InstanceKlass resolvedKlass() {
        if (instanceKlass == null) {
            resolveKlassRef();
        }
        return instanceKlass;
    }

    /**
     * 解析类符号引用（对应 Go 的 resolveClassRef）
     *
     * 步骤：
     * 1. 从当前类的常量池获取类加载器
     * 2. 使用类加载器加载目标类
     * 3. 检查访问权限：目标类是否对当前类可见
     * 4. 保存解析结果到 klass 字段
     *
     * @throws IllegalAccessError 如果当前类无法访问目标类
     */
    private void resolveKlassRef() {
        // 获取当前类（引用该符号的类）
        InstanceKlass c = runtimeConstantPool.getInstanceKlass();
        // 获取类加载器
        ClassLoader loader = c.getClassLoader();
        // 加载目标类
        InstanceKlass d = loader.loadClass(className);

        // 检查访问性：目标类d是否对当前类（c）可见
        if (!d.isAccessibleTo(c)) {
            throw new IllegalAccessError(
                    "Class " + d.getName() + " cannot access " + c.getName()
            );
        }

        // 保存解析结果
        this.instanceKlass = d;
    }
}
